package com.algorithm.dima.dap;

import java.util.ArrayList;
import com.algorithm.basic.BasicMoead;
import com.problem.dima.DAPProblem;
import com.util.bean.METHOD;
import com.util.random.RandomGenerator;
import com.util.solution.impl.DAPSolution;

public class MOEAD extends BasicMoead{
	private DAPProblem problem;
	private int run_num;
	private int niche = 20;
	private int method;

	public MOEAD(DAPProblem problem, int type, int run_num, int method){
		super(problem.obj_num, type);
		this.problem = problem;
		this.run_num = run_num;
		this.method = method;
		weights = new double[problem.sub_num*problem.obj_num];
		nicheNeighbors = new int[problem.sub_num][niche];
		boolean ret = initialWeights(problem.sub_num, niche);
		if(!ret) System.exit(0);
		this.bind(this.problem, this.method);
	}
	
	public void initialIdealPoint(){
		for(int i=0;i<problem.sub_num;i++){
			int [] values = problem.solutionArray[i].object_val;
			this.udpateIdealPoint(values);
		}
	}
	public void execute(int iteration){
		long startMili=System.currentTimeMillis();
		for(int i = 0;i<iteration;i++){
			System.out.println("iteration of : "+(i+1));
			this.executeMoead();
		}
		long endMili=System.currentTimeMillis();
		System.out.println((endMili-startMili)/1000+" s ");
		String fileName;
		if(this.method == METHOD.WS){
			fileName = "files/results/dima/dap/moead/"+this.problem.devNum+"-"+this.problem.posNum+"_ws_"+run_num+".txt";
		}else if(this.method == METHOD.TCH){
			fileName = "files/results/dima/dap/moead/"+this.problem.devNum+"-"+this.problem.posNum+"_tch_"+run_num+".txt";
		}else{
			fileName = "files/results/dima/dap/moead/"+this.problem.devNum+"-"+this.problem.posNum+"_pbi_"+run_num+".txt";
		}
		problem.saveResults(fileName);
	}
	
	public void executeMoead(){
		for(int i=0;i<problem.sub_num;i++){
			DAPSolution curSolution = problem.solutionArray[i];
			if(curSolution.isSearched()==false){
				problem.solutionArray[i].setSearched(true);
				try {
					DAPSolution s = curSolution.clone();
					this.generateNeighborhood(s);
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * generate the neighborhood of s
	 * @param s
	 */
	public void generateNeighborhood(DAPSolution node){
		 int [] seq = new int[this.problem.devNum*this.problem.posNum];
		    int [] allocated = new int[this.problem.devNum*this.problem.posNum];
		    int [] curObjVal = new int[this.problem.obj_num];
		    int choseNum = 2;//chose two positions
		    int loop = 2;//the number of loops
		    ArrayList<Integer> oneSet = new ArrayList<Integer>();
		    for(int i=0;i<this.problem.posNum*this.problem.devNum;i++)
		        if(node.sequence[i]==1) oneSet.add(i);
		    int len = oneSet.size();
		    for(int iter=0;iter<loop;iter++){
		        int  [] randNum = RandomGenerator.permutation_array(0,len-1);
		        for(int i=0;i<len-choseNum;i+=2){
		        	seq	= node.sequence.clone();
		        	allocated = node.allocated.clone();
		        	curObjVal = node.object_val.clone();
		            int index1 = oneSet.get(randNum[i]);
		            int index2 = oneSet.get(randNum[i+1]);
		            seq[index1] = 0;
		            seq[index2] = 0;
		            curObjVal[0] -= this.problem.MassMatrix[index1];
		            curObjVal[0] -= this.problem.MassMatrix[index2];
		            curObjVal[1] -= this.problem.OICMatrix[index1];
		            curObjVal[1] -= this.problem.OICMatrix[index2];
		            int devIndex1 = index1 % this.problem.devNum;
		            int devIndex2 = index2 % this.problem.devNum;
		            int posIndex1 = index1 / this.problem.devNum;
		            int posIndex2 = index2 / this.problem.devNum;
		            this.problem.releaseRSC(allocated,devIndex1,posIndex1);
		            this.problem.releaseRSC(allocated,devIndex2,posIndex2);
		            for(int j = 0;j < this.problem.posNum;j ++){
		                for(int k = 0;k < this.problem.posNum;k ++){
		                    if(j==k && this.problem.segArray[devIndex1*this.problem.devNum+devIndex2]==1) continue;
		                    if(!this.problem.judgeRsc(allocated, devIndex1, j)
		                    && !this.problem.judgeSeg(seq, j*this.problem.devNum, devIndex1)
		                    && !this.problem.judgeRsc(allocated, devIndex2, k)
		                    && !this.problem.judgeSeg(seq, k*this.problem.devNum,devIndex2)){
		                        int [] tempObjVal = new int[2];
		                        tempObjVal[0] = curObjVal[0]+this.problem.MassMatrix[j*this.problem.devNum+devIndex1];
		                        tempObjVal[0] += this.problem.MassMatrix[k*this.problem.devNum+devIndex2];
		                        tempObjVal[1] = curObjVal[1]+this.problem.OICMatrix[j*this.problem.devNum+devIndex1];
		                        tempObjVal[1] += this.problem.OICMatrix[k*this.problem.devNum+devIndex2];
		                        if(tempObjVal[0]>=node.object_val[0] && tempObjVal[1]>=node.object_val[1])
		                            continue;
		                        DAPSolution newNode = new DAPSolution(this.problem.obj_num, -1);
		                        newNode.sequence = seq.clone();
		                        newNode.sequence[j*this.problem.devNum+devIndex1]=1;
		                        newNode.sequence[k*this.problem.devNum+devIndex2]=1;
		                        newNode.object_val = tempObjVal.clone();
		                        newNode.allocated = allocated.clone();
		                        newNode.index = node.index;
		                        for(int m=0;m<this.problem.rscNum;m++){
		                            newNode.allocated[m*this.problem.posNum+j]+=this.problem.devRscArray[m*this.problem.devNum+devIndex1];
		                            newNode.allocated[m*this.problem.posNum+k]+=this.problem.devRscArray[m*this.problem.devNum+devIndex2];
		                        }
		                        this.udpateSubSolutions(newNode);
		                    }
		                }
		            }
		        }
		    }
	}
	public boolean udpateSubSolutions(DAPSolution s){
		this.udpateIdealPoint(s.object_val);
		boolean ret = false;
		for(int i=0;i<niche;i++){
			DAPSolution curSolution = problem.solutionArray[this.nicheNeighbors[s.index][i]];
			double fitness = 0;
			if(this.method == METHOD.WS){
				fitness = getWsValue(curSolution.index, s.object_val);
			}else if(this.method == METHOD.TCH){
				curSolution.fitness = getTchValue(curSolution.index, curSolution.object_val);
				fitness = getTchValue(curSolution.index, s.object_val);
			}else{
				curSolution.fitness = getPbiValue(curSolution.index, curSolution.object_val);
				fitness = getPbiValue(curSolution.index, s.object_val);
			}
			if(curSolution.fitness>fitness){
				curSolution.fitness = fitness;
				curSolution.devNum = s.devNum;
				curSolution.posNum = s.posNum;
				curSolution.sequence = s.sequence.clone();
				curSolution.allocated = s.allocated.clone();
				curSolution.object_val = s.object_val.clone();
				curSolution.setSearched(false);
				ret = true;
			}
		}
		return ret;
	}
	
	public static void main(String[]args){
		for(int i=0;i<20;i++){
			DAPProblem dap = new DAPProblem();
			MOEAD moead = new MOEAD(dap, -1, i, 2);
			moead.execute(1000);
		}
	}
}
